package hottargui.standard;

import hottargui.framework.Game;
import hottargui.framework.GameData;
import hottargui.framework.GameListener;
import hottargui.framework.GameObjectServer;
import hottargui.framework.Player;
import hottargui.framework.PlayerColor;
import hottargui.framework.Position;
import hottargui.framework.State;
import hottargui.framework.TarguiFactory;
import hottargui.framework.TarguiState;
import hottargui.framework.Tile;

import java.util.Iterator;

public class StandardGame implements Game {

	TarguiState currentState;
	TarguiFactory factory;
	GameObjectServer objectServer;

	public StandardGame(TarguiFactory aFactory) {
		factory = aFactory;
		objectServer = factory.getGameObjectServer();
	}

	public void init() {
		// initialize state
		setState(factory.getNewGameState(this));
		// This is set here to avoid calls to rolldie in newgame-state
		// throwing exceptions
		objectServer.getGameData().setPlayerInTurn(PlayerColor.None);
	}

	public TarguiFactory getFactory() {
		return factory;
	}

	public GameObjectServer getGameObjectServer() {
		return objectServer;
	}

	public void newGame() {
		currentState.newGame();
		for (Tile t : objectServer.getGameData().getBoardConfiguration()) {
			notifyTileChange(t);
		}
	}

	/** return a specific tile */
	public Tile getTile(Position p) {
		GameData gd = objectServer.getGameData();
		return gd.getTile(p.getRow(), p.getColumn());
	}

	public Player getPlayerInTurn() {
		return objectServer.getGameData().getPlayerInTurn();
	}

	public State getState() {
		return currentState.getState();
	}

	public boolean move(Position from, Position to, int count) {
		return currentState.move(from, to, count);
	}

	public boolean buy(int count, Position deploy) {
		return currentState.buy(count, deploy);
	}

	public PlayerColor turnCard() {
		PlayerColor newPlayer = currentState.turnCard();
		notifyPlayerChange(newPlayer);
		return newPlayer;
	}

	public void rollDie() {
		currentState.rollDie();
		notifyDieChange();
		notifyBoardChange();
		notifyPlayerChange(getPlayerInTurn().getColor()); //rar at have i gamma varianten
	}

	public int getDieValue() {
		return getGameObjectServer().getGameData().getLastDieRoll();
	}

	public void setState(TarguiState newState) {
		this.currentState = newState;

		notifyStateChange(this.currentState);
		notifyBoardChange();
	}

	public Iterator<? extends Tile> getBoardIterator() {
		return objectServer.getGameData().getBoardConfiguration().iterator();
	}

	public PlayerColor getWinner() {
		PlayerColor winner = currentState.getWinner();
		notifyWinnerChange(winner);
		return winner;
	}

	/**
	 * Functions for GUI integration
	 */

	public GameListener listener = null;

	public void addGameListener(GameListener observer) {
		if (listener != null)
			throw new RuntimeException("AlphaGame only supports one listener.");
		listener = observer;
	}

	public void report(String s) {
		System.out.println(s); // backup
		if (listener != null) {
			listener.report(s);
		}
	}

	public void notifyStateChange(TarguiState state) {
		report("State er: " + state.getState());
		if (listener != null) {
			listener.updateTool(state.getState());
		}
	}

	public void notifyBoardChange() {
		Iterator<? extends Tile> boardIt = getBoardIterator();
		while (boardIt.hasNext()) {
			notifyTileChange(boardIt.next());
		}
	}

	public void notifyTileChange(Tile tile) {
		if (listener != null) {
			listener.updateTile(tile);
		}
	}

	public void notifyDieChange() {
		if (listener != null) {
			listener.updateDie(getDieValue());
		}
	}

	public void notifyPlayerChange(PlayerColor thisPlayer) {
		System.out.println("Player in turn is "+thisPlayer);
		if (listener != null) {
			listener.updatePlayer(thisPlayer);
		}
	}

	public void notifyWinnerChange(PlayerColor thisPlayer) {
		if (listener != null) {
			listener.updateWinner(thisPlayer);
		}
	}

	public void yieldAttack() {
		currentState.yieldAttack();
	}
	
	public void skip() {
		currentState.skip();
	}

}
